; Inno Setup 脚本 - LocalDnsService 安装程序
; 作者: huobing

#define MyAppName "LocalDnsService"
#define MyAppExeName "LocalDnsService.exe"
#define MyAppAssocName "LocalDnsService"
#define MyAppAssocExt ".exe"
#define MyAppDesc "DNS服务应用程序"
#define MyAppCopyright "Copyright © huobing 2025"
#define MyAppPublisher GetStringFileInfo("bin\\Release\\net8.0\\win-x64-no-runtime\\LocalDnsService.exe", "CompanyName")
#define MyAppURL GetStringFileInfo("bin\\Release\\net8.0\\win-x64-no-runtime\\LocalDnsService.exe", "LegalTrademarks")
#ifndef MyAppVersion
#define MyAppVersion GetStringFileInfo("bin\\Release\\net8.0\\win-x64-no-runtime\\LocalDnsService.exe", "ProductVersion")
#endif

[Setup]
; 应用程序基本信息
AppId={{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
AppCopyright={#MyAppCopyright}
DefaultDirName={autopf}\{#MyAppName}
DefaultGroupName={#MyAppName}
AllowNoIcons=yes
OutputDir=bin\Release
OutputBaseFilename=LocalDnsService-Setup-{#MyAppVersion}
SetupIconFile=Ico\256.ico
Compression=lzma
SolidCompression=yes
WizardStyle=modern
PrivilegesRequired=admin
ArchitecturesAllowed=x64compatible
ArchitecturesInstallIn64BitMode=x64compatible
; 显示进度条详情
UseSetupLdr=yes
ShowLanguageDialog=yes

; 安装程序语言
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"

; 安装程序任务
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "installservice"; Description: "安装为Windows服务（开机自启动）"; GroupDescription: "启动选项"; Flags: CheckedOnce

; 安装程序文件
[Files]
; 使用发布输出的框架依赖目录，包含所有所需文件
Source: "bin\Release\net8.0\win-x64-no-runtime\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs

; 保留文档与图标
Source: "docs\*"; DestDir: "{app}\docs"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "Conf\*"; DestDir: "{app}\Conf"; Flags: ignoreversion recursesubdirs createallsubdirs
Source: "Ico\256.ico"; DestDir: "{app}"; Flags: ignoreversion

; 开始菜单快捷方式
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\256.ico"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; IconFilename: "{app}\256.ico"; Tasks: desktopicon
Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}"

; 卸载信息
[UninstallDelete]
Type: filesandordirs; Name: "{app}\Conf"
Type: filesandordirs; Name: "{app}\Logs"
Type: files; Name: "{app}\Logs\*.log"

; 自定义安装程序代码
[Code]
const
  WM_SETTINGCHANGE = $001A;
  UninstallRegKey = '{#SetupSetting("AppId")}_is1';

// 读取已安装版本的卸载路径（从注册表 UninstallString）
function GetExistingUninstallerPath(): string;
var
  s: string;
begin
  s := '';
  if not RegQueryStringValue(HKLM, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + UninstallRegKey, 'UninstallString', s) then
    RegQueryStringValue(HKCU, 'Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\' + UninstallRegKey, 'UninstallString', s);
  if s <> '' then
  begin
    s := RemoveQuotes(s);
    // 如果包含参数，仅取可执行文件路径
    if Pos(' ', s) > 0 then s := Copy(s, 1, Pos(' ', s) - 1);
    Result := s;
    exit;
  end;
  Result := '';
end;

// 检查.NET 8.0运行时是否已安装
function IsDotNet8Installed: Boolean;
var
  ErrorCode: Integer;
  ResultCode: Integer;
  Output: AnsiString;
begin
  Result := False;
  if Exec('dotnet', '--list-runtimes', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
  begin
    if ResultCode = 0 then
    begin
      if Exec('cmd.exe', '/c dotnet --list-runtimes | findstr "Microsoft.NETCore.App 8.0"', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
      begin
        Result := (ResultCode = 0);
      end;
    end;
  end;
end;

// 准备安装时检查运行时与已安装状态
function InitializeSetup(): Boolean;
var
  ResultCode: Integer;
  UninsPath: string;
begin
  Result := True;

  // 通过注册表检测是否已安装，要求先卸载后再安装
  UninsPath := GetExistingUninstallerPath();
  if UninsPath <> '' then
  begin
    if MsgBox('检测到已安装版本，需要先卸载后再安装。是否立即卸载？', mbConfirmation, MB_YESNO) = IDYES then
    begin
      if not Exec(UninsPath, '/VERYSILENT /SUPPRESSMSGBOXES /NORESTART /SP-', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
      begin
        MsgBox('卸载过程启动失败，安装已取消。', mbError, MB_OK);
        Result := False;
        exit;
      end;
    end
    else
    begin
      Result := False;
      exit;
    end;
  end;

  // 检查.NET 8.0运行时（仅无运行时安装包）
  if not IsDotNet8Installed then
  begin
    if MsgBox('检测到系统未安装.NET 8.0运行时，此应用程序需要.NET 8.0运行时才能正常运行。' + #13#10 + #13#10 +
              '点击"是"将打开.NET 8.0运行时下载页面，请下载并安装后重新运行此安装程序。' + #13#10 +
              '点击"否"将退出安装程序。', mbConfirmation, MB_YESNO) = IDYES then
    begin
      ShellExec('open', 'https://dotnet.microsoft.com/download/dotnet/8.0', '', '', SW_SHOWNORMAL, ewNoWait, ResultCode);
    end;
    Result := False;
    exit;
  end;
end;

// 安装完成后提示
procedure CurStepChanged(CurStep: TSetupStep);
var
  CurrentPath: string;
  ResultCode: Integer;
begin
  if CurStep = ssPostInstall then
  begin
    CreateDir(ExpandConstant('{app}\Logs'));
    RegWriteStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'LOCAL_DNS_SERVICE_HOME', ExpandConstant('{app}'));
    CurrentPath := '';
    RegQueryStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'PATH', CurrentPath);
    if Pos(';' + ExpandConstant('{app}') + ';', ';' + CurrentPath + ';') = 0 then
    begin
      RegWriteStringValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'PATH', CurrentPath + ';' + ExpandConstant('{app}'));
      SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE, 0, 0);
    end;
    
    // 如果选择了安装服务选项
    if WizardIsTaskSelected('installservice') then
    begin
      // 使用sc命令安装服务
      Exec('sc.exe', 'create LocalDnsService binPath= "\"' + ExpandConstant('{app}') + '\LocalDnsService.exe\" --windows-service" DisplayName= "本地DNS服务" start= auto', '', SW_HIDE, ewNoWait, ResultCode);
      
      // 启动服务
      Exec('sc.exe', 'start LocalDnsService', '', SW_HIDE, ewNoWait, ResultCode);
    end;
  end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
  ResultCode: Integer;
  ServiceExists: Boolean;
  ServiceState: string;
begin
  if CurUninstallStep = usUninstall then
  begin
    // 检查服务是否存在
    ServiceExists := False;
    if Exec('sc.exe', 'query LocalDnsService', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
    begin
      ServiceExists := (ResultCode = 0);
    end;
    
    if ServiceExists then
    begin
      // 停止服务，增加等待时间确保服务完全停止
      Exec('sc.exe', 'stop LocalDnsService', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
      
      // 等待3秒让服务有足够时间停止
      Sleep(3000);
      
      // 删除服务
      Exec('sc.exe', 'delete LocalDnsService', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
    end;
    
    // 清理环境变量
    RegDeleteValue(HKLM, 'SYSTEM\CurrentControlSet\Control\Session Manager\Environment', 'LOCAL_DNS_SERVICE_HOME');
  end;
end;